package com.cloudbroker.bcs.csvc.lightinvesting.facade.service.aspect;

import com.cloudbroker.bcs.common.annotation.*;
import com.cloudbroker.bcs.common.exception.HSBCSErrInfoException;
import com.cloudbroker.bcs.common.util.PrintUtil;
import com.cloudbroker.bcs.csvc.lightinvesting.api.vo.request.base.LedForm;
import com.cloudbroker.bcs.platform.ltb.bizapi.constants.HSBCPSErrorCodes;
import com.cloudbroker.bcs.platform.ltb.bizapi.constants.type.UserType;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

/**
 * Created by tianrui on 2016/8/2.
 */
public class AuthCheckAspect {

    private static final String CLASS_NAME = AuthCheckAspect.class.getName();

    private static final Logger LOGGER = LoggerFactory.getLogger(CLASS_NAME);

    public AuthCheckAspect() {
        PrintUtil.printComponentLoaded(LOGGER, CLASS_NAME);
    }

    public Object checkAuth(ProceedingJoinPoint pjp) throws Throwable {
        // 在Spring的环境里，signature就是MethodSignature
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        // 获取Method
        Method method = methodSignature.getMethod();

        //走后台接口全都需要user_token
        if ( !method.isAnnotationPresent(NoToken.class)) {
            // 聚合class和method上的权限，并缓存
            RequiredPermissions requiredPermissionsAnn = method.getAnnotation(RequiredPermissions.class);
            String[] requiredPermissions = null;
            if (null != requiredPermissionsAnn) {
                requiredPermissions = requiredPermissionsAnn.value();
            }
            Object result = null;
            try {
                // 检查登录及权限
                try {
                    checkAndBindLoginInfo(pjp.getArgs(), requiredPermissions,
                            method.isAnnotationPresent(NoRefreshSession.class), method);

                } catch (HSBCSErrInfoException e) {
                    if (e.isErrorIn(HSBCPSErrorCodes.NOT_LOGGED, HSBCPSErrorCodes.NO_PERMISSION,
                            HSBCPSErrorCodes.ClientErr.NO_SUCH_CLIENT, HSBCPSErrorCodes.VISITOR_NOT_LOGGED)) {
                        result = method.getReturnType().newInstance();
                        result.getClass().getMethod("setError_no", String.class).invoke(result,e.getErrorNo());
                        return result;
                    }
                    throw e;
                }
                // 执行业务
                result = pjp.proceed();
            } finally {
            }
            return result;
        } else {
            // 执行业务
            return pjp.proceed();
        }
    }

    private void checkAndBindLoginInfo(Object[] args, String[] requiredPermissions, boolean noRefresh, Method method) {
        for (Object arg : args) {
            UserCache sessionIdentity = checkSessionPermission((LedForm) arg, requiredPermissions,
                    noRefresh, method);
            break;
            }
        }
    private UserCache checkSessionPermission(LedForm param, String[] requiredPermissions, boolean noRefresh,  Method method) {

        // 获取携带的access_token
        String access_token = param.getUser_token();
        // 获取会话身份对象
        UserCache identity = UserTokenUtil.queryUserToken(access_token);
        if (null == identity) {
            if (access_token.indexOf("visitor") != -1){
                throw new HSBCSErrInfoException(HSBCPSErrorCodes.VISITOR_NOT_LOGGED);
            }
            // 如果会话身份对象不存在则表示未登录或已超时
            throw new HSBCSErrInfoException(HSBCPSErrorCodes.NOT_LOGGED);
        } else if (String.valueOf(UserType.VISITOR.getVal()).equals(identity.getUser_type())) {
            if (!method.isAnnotationPresent(NoLogin.class)
                    && !method.getDeclaringClass().isAnnotationPresent(NoLogin.class)){
                throw new HSBCSErrInfoException(HSBCPSErrorCodes.NOT_LOGGED);
            }
        } else {
            if (!noRefresh) {
                // 刷新会话，重置超时时间
                UserTokenUtil.updateUserToken(access_token, identity);
            }
        }
        return identity;
    }

}
